package com.wuyan.web.form.api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wuyan.web.base.aop.ApiLogAnnotation;
import com.wuyan.web.base.helper.BaseApi;
import com.wuyan.web.base.helper.auth.LoginInfo;
import com.wuyan.web.base.helper.rep.RepBody;
import com.wuyan.web.base.helper.rep.RepCodeEnum;
import com.wuyan.web.base.helper.rep.RepHelper;
import com.wuyan.web.base.helper.rep.RepPageData;
import com.wuyan.web.base.helper.req.CustomQueryHelper;
import com.wuyan.web.base.helper.req.CustomQueryOrderParams;
import com.wuyan.web.base.helper.req.CustomQueryParams;
import com.wuyan.web.form.entity.PubForm;
import com.wuyan.web.form.helper.FormHelper;
import com.wuyan.web.form.helper.email.EmailHelper;
import com.wuyan.web.form.service.FormService;
import com.wuyan.web.form.service.PubFormService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

@RestController
@RequestMapping("/api")
@Slf4j
public class FormApi extends BaseApi implements RepHelper {

    @Autowired
    private FormService formService;

    @Autowired
    private PubFormService pubFormService;

    @Autowired
    private ObjectMapper mapper;

    @Autowired
    private FormHelper formHelper;

    /**
     * 根据表单名称创建新增表单数据
     *
     * @param form  表单
     * @param table 表名
     * @return RepBody<Object>
     */
    @PostMapping("/{table}")
    @ApiLogAnnotation(name = "FormData:create")
    public RepBody<Map<String, Object>> create(HttpServletRequest request,
                                               @RequestBody @Validated Map<String, Object> form,
                                               @PathVariable("table") String table) throws Exception {
        PubForm pubForm = tableExists(table);
        if (null == pubForm) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }
        if (0 == pubForm.getStatus()) {
            return error(RepCodeEnum.ERR_FORM_DISABLED);
        }

        LoginInfo loginInfo = getLoginInfo(request);
        // 强制登录检查
        Set<Integer> addForceLogin = formHelper.getAddForceLogin();
        if (addForceLogin.contains(pubForm.getId()) && null == loginInfo) {
            return error(RepCodeEnum.ERR_LOGIN_EXPIRE);
        }

        Map<String, Object> obj = formService.create(table, form, loginInfo, pubForm);
        return ok(obj);
    }

    /**
     * 批量插入|更新
     *
     * @param form  数据集合
     * @param table 表单
     * @return RepBody<Object>
     * @throws Exception e
     */
    @PostMapping("/{table}/plist")
    @ApiLogAnnotation(name = "FormData:plist")
    public RepBody<Integer> plist(HttpServletRequest request,
                                  @RequestBody @Validated List<Map<String, Object>> form,
                                  @PathVariable("table") String table)
            throws Exception {
        PubForm pubForm = tableExists(table);
        if (null == pubForm) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }
        if (1 == pubForm.getDisabled() || 0 == pubForm.getStatus()) {
            return error(RepCodeEnum.ERR_FORM_DISABLED);
        }

        LoginInfo loginInfo = getLoginInfo(request);
        // 强制登录检查
        Set<Integer> addForceLogin = formHelper.getAddForceLogin();
        if (addForceLogin.contains(pubForm.getId()) && null == loginInfo) {
            return error(RepCodeEnum.ERR_LOGIN_EXPIRE);
        }

        int num = form.stream().map(item -> {
            try {
                if (null != item.get("id") && StringUtils.isNotBlank(item.get("id").toString())) {
                    String id = item.get("id").toString();
                    Map map = formService.get(id, table);
                    if (null == map) {
                        return formService.create(table, item, loginInfo, pubForm);
                    } else {
                        return formService.update(id, table, item);
                    }
                } else {
                    return formService.create(table, item, loginInfo, pubForm);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return null;
            }
        }).mapToInt(obj -> null == obj ? 0 : 1).sum();
        return ok(num);
    }

    /**
     * 更新
     *
     * @param form  表单数据
     * @param table 表单名
     * @return RepBody<Object>
     * @throws Exception e
     */
    @PutMapping("/{table}/{id}")
    @ApiLogAnnotation(name = "FormData:update")
    public RepBody<Map<String, Object>> update(@RequestBody @Validated Map<String, Object> form,
                                               @PathVariable("table") String table,
                                               @PathVariable("id") String id)
            throws Exception {
        PubForm pubForm = tableExists(table);
        if (null == pubForm) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }
        if (0 == pubForm.getStatus()) {
            return error(RepCodeEnum.ERR_FORM_DISABLED);
        }

        long update = formService.update(id, table, form);

        return update > 0 ? ok(form) : error(RepCodeEnum.ERR_UPDATE);
    }

    /**
     * 删除数据
     *
     * @param table 表单名称
     * @param id    id组
     * @return RepBody<Object>
     * @throws Exception e
     */
    @DeleteMapping("/{table}/{id}")
    @ApiLogAnnotation(name = "FormData:delete")
    public RepBody<?> delete(@PathVariable("table") String table, @PathVariable("id") String[] id)
            throws Exception {
        PubForm pubForm = tableExists(table);
        if (null == pubForm) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }

        long delete = formService.delete(id, table, pubForm);

        return delete > 0 ? ok() : error(RepCodeEnum.ERR_DELETE);
    }

    @GetMapping("/{table}/{id}")
    @ApiLogAnnotation(name = "FormData:get")
    public RepBody<Map> get(@PathVariable("table") String table, @PathVariable("id") String id)
            throws Exception {
        if (null == tableExists(table)) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }

        return ok(formService.get(id, table));
    }

    /**
     * 根据表单ID，获取表单数据
     *
     * @param id           表单ID
     * @param isPage       是否分页
     * @param page         当前页
     * @param limit        分页大小
     * @param params       查询参数
     * @param ordersParams 排序参数
     * @return Map<String, Object>
     */
    @SneakyThrows
    @GetMapping("/page/formId/{id}")
    @ApiLogAnnotation(name = "FormData:pageByFormId")
    public RepBody<Map<String, Object>> pageByFormId(@PathVariable("id") Integer id,
                                                     @RequestParam(value = "isPage", required = false, defaultValue = "true") Boolean isPage,
                                                     @RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
                                                     @RequestParam(value = "limit", required = false, defaultValue = "15") Integer limit,
                                                     @RequestParam(value = "params", required = false, defaultValue = "[]") String params,
                                                     @RequestParam(value = "orders", required = false, defaultValue = "[]") String ordersParams) {
        Optional<PubForm> optionalPubForm = pubFormService.get(id);
        if (!optionalPubForm.isPresent()) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }

        // 查询参数
        List<CustomQueryParams> paramsList = mapper.readValue(params, new TypeReference<List<CustomQueryParams>>() {
        });
        // 排序参数
        List<CustomQueryOrderParams> orderList = mapper.readValue(ordersParams, new TypeReference<List<CustomQueryOrderParams>>() {
        });

        RepPageData<Map> repPageData = formService.page(optionalPubForm.get().getFormRef(), isPage, page, limit, paramsList, orderList);
        Map<String, Object> data = new HashMap<>();
        data.put("form", optionalPubForm.get());
        data.put("pageData", repPageData);
        return ok(data);
    }


    /**
     * @param isPage       是否分页
     * @param page         当前页
     * @param limit        条目数
     * @param params       查询参数：数组形式JSON字符串
     * @param ordersParams 排序参数：数组形式JSON字符串
     * @return RepBody<RepPageData < Map>>
     */
    @SneakyThrows
    @GetMapping("/{table}")
    @ApiLogAnnotation(name = "FormData:page")
    public RepBody<RepPageData<Map>> page(@PathVariable("table") String table,
                                          @RequestParam(value = "isPage", required = false, defaultValue = "true") Boolean isPage,
                                          @RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
                                          @RequestParam(value = "limit", required = false, defaultValue = "15") Integer limit,
                                          @RequestParam(value = "params", required = false, defaultValue = "[]") String params,
                                          @RequestParam(value = "orders", required = false, defaultValue = "[]") String ordersParams) {
        if (null == tableExists(table)) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }

        // 查询参数
        List<CustomQueryParams> paramsList = mapper.readValue(params, new TypeReference<List<CustomQueryParams>>() {
        });

        // 排序参数
        List<CustomQueryOrderParams> orderList = mapper.readValue(ordersParams, new TypeReference<List<CustomQueryOrderParams>>() {
        });

        return ok(formService.page(table, isPage, page, limit, paramsList, orderList));
    }

    /**
     * 为某个集合建立全文索引
     *
     * @param table 集合名称
     * @return RepBody<Boolean>
     * @throws JsonProcessingException   e
     * @throws InvocationTargetException e
     * @throws InstantiationException    e
     * @throws IllegalAccessException    e
     * @throws NoSuchMethodException     e
     * @throws ClassNotFoundException    e
     */
    @GetMapping("/{table}/ensure-index-full-text")
    @ApiLogAnnotation(name = "FormData:ensureIndexFullText")
    public RepBody<Boolean> ensureIndexFullText(@PathVariable("table") String table)
            throws JsonProcessingException, InvocationTargetException,
            InstantiationException, IllegalAccessException,
            NoSuchMethodException, ClassNotFoundException {
        if (null == tableExists(table)) {
            return error(RepCodeEnum.ERR_NO_FORM);
        }

        boolean res = formService.ensureIndexFullText(table);

        return ok(res);
    }

    /**
     * 监测表单名是否存在
     *
     * @param table 表单名
     * @return RepBody<Boolean>
     */
    @GetMapping("/{table}/exists")
    @ApiLogAnnotation(name = "FormData:exists")
    public RepBody<PubForm> exists(@PathVariable("table") String table)
            throws JsonProcessingException, ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, InstantiationException, IllegalAccessException {
        return ok(tableExists(table));
    }

    /**
     * 监测表单名是否存在
     *
     * @param table 名称
     * @return boolean
     * @throws JsonProcessingException   e
     * @throws ClassNotFoundException    e
     * @throws NoSuchMethodException     e
     * @throws InvocationTargetException e
     * @throws InstantiationException    e
     * @throws IllegalAccessException    e
     */
    public PubForm tableExists(String table) throws JsonProcessingException, ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, InstantiationException, IllegalAccessException {

        List<CustomQueryParams> params = new ArrayList<>();
        if (StringUtils.isBlank(table)) {
            return null;
        } else {
            CustomQueryParams param = CustomQueryParams.builder()
                    .left("formRef")
                    .op("eq")
                    .right(new String[]{table})
                    .build();
            params.add(param);
        }

        CustomQueryHelper<PubForm> queryHelper = CustomQueryHelper.init(PubForm.class, mapper.writeValueAsString(params), "[]");
        RepPageData<PubForm> data = pubFormService.page(queryHelper.getPredicates(), queryHelper.getOrders(), false, 0, 0);

        List<PubForm> list = data.getList();

        return null != list && !list.isEmpty() ? list.get(0) : null;
    }
}
